package cc.yugu.yhdw.webserver.service.basic;

import cc.yugu.yhdw.common.domain.basic.Menu;
import cc.yugu.yhdw.common.domain.basic.Oper;
import cc.yugu.yhdw.common.domain.basic.Role;
import cc.yugu.yhdw.common.domain.basic.RoleOper;
import cc.yugu.yhdw.common.entity.json.ExtResult;
import cc.yugu.yhdw.common.entity.pagination.Page;
import cc.yugu.yhdw.common.entity.tree.Node;
import cc.yugu.yhdw.common.entity.tree.NodeModel;
import cc.yugu.yhdw.common.utils.YhdwUtils;
import cc.yugu.yhdw.webserver.persistence.basic.*;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * 角色业务
 * 
 * @Date:Created in 2018/7/4 11:29
 * @Author:
 * @Modified By: zjn 2018/7/4 11:29
 */ 
@Service
public class RoleService {

    @Autowired
    RoleMapper roleMapper;
    @Autowired
    MenuMapper menuMapper;
    @Autowired
    OperMapper operMapper;
    @Autowired
    RoleOperMapper roleOperMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    AgentMapper agentMapper;
    /**
    * 查询，返回角色信息
    *
    * @Param: [id]
    * @Return: cc.yugu.yhdw.common.domain.basic.Role
    * @Author By: zjn 2018/7/4  11:29
    */
    public Role find(int id) {
        // 根据主键查询
        Role role = roleMapper.find(id);
        if (role!=null&&role.getAgentId() != null && role.getAgentId() != 0) {
            // 设置运营商名称
            role.setAgentName(agentMapper.find(role.getAgentId())!=null?agentMapper.find(role.getAgentId()).getAgentName():"");
        }
        return role;
    }
    /**
    * 根据运营商id查询表，并将结果按照主键降序排列，返回
    * 
    * @Param: [agentId]
    * @Return: java.util.List<cc.yugu.yhdw.common.domain.basic.Role>
    * @Author By: zjn 2018/7/4  11:32
    */ 
    public List<Role> findByAgent(int agentId) {
        return roleMapper.findByAgent(agentId);
    }

    /**
    * 分页查询
    * 
    * @Param: [search]
    * @Return: cc.yugu.yhdw.common.entity.pagination.Page
    * @Author By: zjn 2018/7/4  11:32
    */ 
    public Page findPage(Role search) {
        Page page = search.buildPage();
        page.setTotalItems(roleMapper.findPageCount(search));
        search.setBeginIndex(page.getOffset());
        page.setResult(roleMapper.findPageResult(search));
        return page;
    }
    /**
    * 查询觉得，返回编号
    * 
    * @Param: [roleId]
    * @Return: java.util.Set<java.lang.String>
    * @Author By: zjn 2018/7/4  11:32
    */ 
    public Set<String> loadOperCode(int roleId) {
        // 根据角色id查询表bas_role_oper 中角色下级（ oper_id）
        List<Integer> operIdList = roleOperMapper.findAll(roleId);
        // 查询表 bas_oper中所有数据
        List<Oper> operList = operMapper.findAll();
        Map<Integer, Oper> operMap = new HashMap<Integer, Oper>();
        for (Oper oper : operList) {
            operMap.put(oper.getId(), oper);
        }

        Set<String> codeSet = new HashSet<String>();
        // 遍历角色下级id
        for (Integer operId : operIdList) {
            Oper oper = operMap.get(operId);
            // 添加 编号
            codeSet.add(oper.getOperCode());
            // 如果依赖不为空
            if (StringUtils.isNotEmpty(oper.getDepend())) {
                // 根据指定 字符 进行切割，返回数组
                String[] depend = StringUtils.split(oper.getDepend(), ",");
                codeSet.addAll(Arrays.asList(depend));
            }
        }
        return codeSet;
    }
    /**
    * 插入
    * 
    * @Param: [role]
    * @Return: cc.yugu.yhdw.common.entity.json.ExtResult
    * @Author By: zjn 2018/7/4  15:47
    */ 
    @Transactional(rollbackFor = Throwable.class)
    public ExtResult create(Role role) {
        try {
            roleMapper.insert(role);

            for (Integer oper : role.getOperList()) {
                RoleOper roleOper = new RoleOper();
                roleOper.setRoleId(role.getId());
                roleOper.setOperId(oper);
                roleOperMapper.insert(roleOper);
            }
        } catch (Exception e) {
            return ExtResult.failResult("操作失败");
        }
        return ExtResult.successResult();
    }
    /**
    * 更新
    * 
    * @Param: [role]
    * @Return: cc.yugu.yhdw.common.entity.json.ExtResult
    * @Author By: zjn 2018/7/4  15:50
    */ 
    @Transactional(rollbackFor = Throwable.class)
    public ExtResult update(Role role) {
        try {
            roleMapper.update(role);
            roleOperMapper.delete(role.getId());
            for (Integer oper : role.getOperList()) {
                RoleOper roleOper = new RoleOper();
                roleOper.setRoleId(role.getId());
                roleOper.setOperId(oper);
                roleOperMapper.insert(roleOper);
            }
        } catch (Exception e) {
            return ExtResult.failResult("操作失败");
        }

        return ExtResult.successResult();
    }
    /**
    * 删除
    * 
    * @Param: [id]
    * @Return: cc.yugu.yhdw.common.entity.json.ExtResult
    * @Author By: zjn 2018/7/4  15:51
    */ 
    public ExtResult delete(int id) {
        try {
            // 查询登录名
            String username = userMapper.hasRecordByProperty("roleId", id);
            if (StringUtils.isNotEmpty(username)) {
                return ExtResult.failResult(String.format("角色被用户[%s]使用，删除失败", username));
            }
            // 根据主键删除
            roleMapper.delete(id);
        } catch (Exception e) {
            return ExtResult.failResult("操作失败");
        }
        return ExtResult.successResult();
    }
    /**
    * 批量删除
    * 
    * @Param: [id]
    * @Return: cc.yugu.yhdw.common.entity.json.ExtResult
    * @Author By: zjn 2018/7/4  16:23
    */ 
    @Transactional(rollbackFor = Throwable.class)
    public ExtResult batchDelete(int[] id) {
        int count = 0;
        try {
            count = 0;
            for (int e : id) {
                String user = userMapper.hasRecordByProperty("roleId", id);
                if (StringUtils.isEmpty(user)) {
                    roleMapper.delete(e);
                    count++;
                }
            }
        } catch (Exception e) {
            return ExtResult.failResult("操作失败");
        }

        return ExtResult.successResult(String.format("成功删除%d条记录", count));
    }
    /**
    * 输出运营商树信息
    * 
    * @Param: [agentId, stream]
    * @Return: void
    * @Author By: zjn 2018/7/4  17:34
    */ 
    public void tree(int agentId, OutputStream stream) throws IOException {

        List<Role> list = roleMapper.findByAgent(agentId);
        List<Node<NodeModel>> roots = new ArrayList<Node<NodeModel>>();
        for (Role role : list) {
            NodeModel nodeModel = new NodeModel();
            Node<NodeModel> root = new Node<NodeModel>(nodeModel);
            nodeModel.setId(role.getId());
            nodeModel.setName(role.getRoleName());
            roots.add(root);
        }

        ObjectMapper objectMapper = new ObjectMapper();
        JsonGenerator json = objectMapper.getJsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
        json.writeStartArray();
        YhdwUtils.writeJson(roots, json);
        json.writeEndArray();
        json.flush();
        json.close();
    }
    /**
    * 输出所有的菜单目录树
    *
    * @Param: [id, stream]
    * @Return: void
    * @Author By: zjn 2018/7/5  10:32
    */
    public void tree(Integer id, OutputStream stream) throws IOException {
        Set<Integer> checkedOper = Collections.EMPTY_SET;
        if (id != null) {
            // 将角色下级id放到集合中
            checkedOper = new HashSet<Integer>(roleOperMapper.findAll(id));
        }
        // 查询后台页面左栏中的所有菜单
        List<Menu> menuList = menuMapper.findAll();
        Map<Integer, Menu> menuMap = new HashMap<Integer, Menu>();
        for (Menu menu : menuList) {
            // key-value 对存储菜单信息
            menuMap.put(menu.getId(), menu);
        }
        // 查询所有角色下级信息（如：新建，列表，修改，删除等）
        List<Oper> operList = operMapper.findAll();
        Map<Integer, Oper> operMap = new HashMap<Integer, Oper>();
        for (Oper oper : operList) {
            operMap.put(oper.getId(), oper);
        }


        Map<Integer, List<Integer>> menuParentMap = makeParentMap(menuMap);
        Map<Integer, List<Integer>> operMenuMap = makeMenuMap(operMap);
        List<Integer> rootMenuIdList = menuMapper.findRoots();

        AtomicInteger seq = new AtomicInteger();

        Node<NodeModel> root = new Node<NodeModel>(new NodeModel());
        root.getData().setId(seq.incrementAndGet());
        root.getData().setName("所有操作");
        root.getData().setLevel(1);
        for (Integer menuId : rootMenuIdList) {
            addSonMenu(seq, menuId, root, menuMap, menuParentMap, operMap, operMenuMap, checkedOper);
        }

        List<Node<NodeModel>> roots = new ArrayList<Node<NodeModel>>();
        roots.add(root);

        ObjectMapper objectMapper = new ObjectMapper();
        JsonGenerator json = objectMapper.getJsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
        json.writeStartArray();
        YhdwUtils.writeJson(roots, json);
        json.writeEndArray();

        json.flush();
        json.close();
    }
    /**
    * 添加子节点菜单
    *
    * @Param: [seq, menuId, parent, menuMap, menuParentMap, operMap, operMenuMap, operIdSet]
    * @Return: void
    * @Author By: zjn 2018/7/5  10:40
    */
    private void addSonMenu(AtomicInteger seq, int menuId, Node<NodeModel> parent, Map<Integer, Menu> menuMap, Map<Integer, List<Integer>> menuParentMap, Map<Integer, Oper> operMap, Map<Integer, List<Integer>> operMenuMap, Set<Integer> operIdSet) {
        Node<NodeModel> node = new Node<NodeModel>(new NodeModel(), parent);
        node.getData().setName(menuMap.get(menuId).getMenuName());
        node.getData().setId(seq.incrementAndGet());
        node.getData().setLevel(parent.getData().getLevel() + 1);
        List<Integer> menuIdList = menuParentMap.get(menuId);
        if (menuIdList != null) {
            for (Integer id : menuIdList) {
                addSonMenu(seq, id, node, menuMap, menuParentMap, operMap, operMenuMap, operIdSet);
            }
        } else {
            List<Integer> operIdList = operMenuMap.get(menuId);
            if (operIdList != null) {
                for (Integer operId : operIdList) {
                    Node<NodeModel> n = new Node<NodeModel>(new NodeModel(), node);
                    Oper oper = operMap.get(operId);
                    n.getData().setId(seq.incrementAndGet());
                    n.getData().setName(oper.getOperName());
                    n.getData().addAttribute("id", operId);
                    n.getData().setLevel(node.getData().getLevel() + 1);
                    if (operIdSet.contains(operId)) {
                        n.getData().setCheckStatus(NodeModel.CheckedStatus.checked);
                    } else {
                        n.getData().setCheckStatus(NodeModel.CheckedStatus.unchecked);
                    }
                }
            }
        }
    }
    /**
    * 构建菜单目录树
    *
    * @Param: [menuMap]
    * @Return: java.util.Map<java.lang.Integer,java.util.List<java.lang.Integer>>
    * @Author By: zjn 2018/7/5  10:41
    */
    private Map<Integer, List<Integer>> makeParentMap(Map<Integer, Menu> menuMap) {
        Map<Integer, List<Integer>> parentMap = new HashMap<Integer, List<Integer>>();
        for (Menu menu : menuMap.values()) {
            if (menu.getParentId() != null) {
                Integer parentId = menu.getParentId();
                List<Integer> v = parentMap.get(parentId);
                if (v != null) {
                    v.add(menu.getId());
                } else {
                    v = new ArrayList<Integer>();
                    parentMap.put(parentId, v);
                    v.add(menu.getId());
                }
            }
        }

        return parentMap;
    }
    /**
    * 构建角色下级目录树
    *
    * @Param: [operMap]
    * @Return: java.util.Map<java.lang.Integer,java.util.List<java.lang.Integer>>
    * @Author By: zjn 2018/7/5  10:41
    */
    private Map<Integer, List<Integer>> makeMenuMap(Map<Integer, Oper> operMap) {
        Map<Integer, List<Integer>> menuMap = new HashMap<Integer, List<Integer>>();
        for (Oper oper : operMap.values()) {
            if (oper.getMenuId() != null) {
                Integer menuId = oper.getMenuId();
                List<Integer> v = menuMap.get(menuId);
                if (v != null) {
                    v.add(oper.getId());
                } else {
                    v = new ArrayList<Integer>();
                    menuMap.put(menuId, v);
                    v.add(oper.getId());
                }
            }
        }

        return menuMap;
    }
}
